#include "main.h"



///TODO:
/*
    Move all particle data and generation to physics engine

    map servers connected and sort them geometrically
    correct how the corrections to particle location are made for server network geometry>solid walls
    send interaction data when connected to a new server
*/

///NOTE_C:throw in anti gravity thing.
///NOTE_D:add commands
    //disconnect from network
    //save local
    //open saved




//////////////////////////////////////////////////////////////////////////////////////////////////////
///MAIN
//////////////////////////////////////////////////////////////////////////////////////////////////////

int main(int argc, char** argv)
{
    //////////////////////////////////////////////////////////////////////////////////////////////////////
    ///Initialize Varriables
    initscr();
    nodelay(stdscr, TRUE);
    printw("Initializing..\n\tVarriables");
    refresh();
    //////////////////////////////////////////////////////////////////////////////////////////////////////

    //input varriables
    int keypressed = 0, commandHistory[3] = {0,0,0};
    //control boolean
    bool exitServer = 0, issuedPrompt = 0, connectionRequest = 1;
    //measure distances, so fun!
    float dx, dy, dz, difference;

    //IP addresses of connected servers
    std::vector <char*> connectedServerIPs;
    //used to push_back server IP addresses
    char temp[32];

    std::string buffer;

    // initialize random seed... add option to use static seed
    srand (time(NULL));

    //color of a particle type, more might be added
    std::vector < particleInformation > particleTypeData (INITIAL_PARTICLE_TYPES);

    //create particle vector
    std::vector<particle> particles(PARTICLE_COUNT);



    //////////////////////////////////////////////////////////////////////////////////////////////////////
    ///Create Particle Properties
    printw("\n\tParticle Type Information");
    refresh();
    //////////////////////////////////////////////////////////////////////////////////////////////////////

    for (int i = 0; i < INITIAL_PARTICLE_TYPES; i ++)
    {
        particleTypeData[i].R = rand() % 256;//0-255
        particleTypeData[i].G = rand() % 256;
        particleTypeData[i].B = rand() % 256;
        particleTypeData[i].A = distribution(generator)/2;//0-1
    }



    //////////////////////////////////////////////////////////////////////////////////////////////////////
    ///Generate Particles
    printw("\n\tParticles");
    refresh();
    //////////////////////////////////////////////////////////////////////////////////////////////////////

    for (int i = 0; i < PARTICLE_COUNT; i++)
    {
        //distribute particle types
        particles[i].type = i%INITIAL_PARTICLE_TYPES;
        //asign each particle a starting location; 0 starting velocity should correct itself
        particles[i].X = distribution(generator)-1;
        particles[i].Y = distribution(generator)-1;
        particles[i].Z = distribution(generator)-1;
        particles[i].quanta = distribution(generator)-1;
    }



    //////////////////////////////////////////////////////////////////////////////////////////////////////
    ///Create 2D Vector For Relative Server Locations; Initialize [0][0].x/y/z As Zeros
    printw("\n\tServer List");
    refresh();
    //////////////////////////////////////////////////////////////////////////////////////////////////////



    //////////////////////////////////////////////////////////////////////////////////////////////////////
    ///Main Loop
    printw("\nDone.\n\nPress RETURN to continue.\n");
    while(keypressed!='\n'){keypressed=getch();}
    buffer = std::string("\n\nRunning Server!\n\nOptions:\n\t1:\tExit\n\t2:\tAdd Connection")+(connectionRequest ? "\n\t3:\tView Connection Request\n" : "\n");
    outputFunction(0, 0, 1, 0, 0, buffer);
    //////////////////////////////////////////////////////////////////////////////////////////////////////

    while (!exitServer)
    {



        //////////////////////////////////////////////////////////////////////////////////////////////////////
        ///Owner Commands
        //////////////////////////////////////////////////////////////////////////////////////////////////////

        if ((keypressed = getch()) != ERR)
        {
            commandHistory[2] = commandHistory[1];
            commandHistory[1] = commandHistory[0];
            commandHistory[0] = keypressed;
        }

        switch (keypressed)
        {
        case ERR://no key
            break;
        case 49://1
            exitServer = 1;
            break;
        case 50://2
            outputFunction(COMMON_SPOT-1,0,1,COMMON_SPOT,0,"WARNING->\tConnecting to another server with a different particle count\n\t\tand different material types can cause awesome\n\t\tswathes of destruction.\nContinue[y/n]?\n");
            break;
        case 51://3
            if (connectionRequest)
            {
                outputFunction(COMMON_SPOT-1,0,1,COMMON_SPOT,0,"");
                printw("WARNING\nYou are aproving a server merge.\nHere are the other server's stats.\nParticles:\t\t%i\nFluid Types:\t\t%i\n\Number Of Entities:\t%i\nGenerate New Types?:\t%i\nBe warned that these will be added to your own;\nthis may cause your server to slow or crash.\nThe additions will be permanent.\nContinue[y/n]?\n:",1,1,1,1);
            }
            else{outputFunction(COMMON_SPOT-1,0,1,COMMON_SPOT,0,"Invalid Entry");}
            break;
        case 121:
            switch (commandHistory[1])
            {
            case 50://Owner answered y to connect to new server
                printw("\n\nPausing Server For Input...\nInput the IP address.\n:\t");
                nodelay(stdscr, FALSE);
                getnstr( temp, sizeof(temp) - 1 );
                nodelay(stdscr, TRUE);
                requestConnection(temp);
                break;
            case 51:
                printw("\n\nCommand not implemented..  make sure to insert real values from connecting server and fix the starting value of connectionRequest to 0");
                break;
            default:
                outputFunction(COMMON_SPOT-1,0,1,COMMON_SPOT,0,"Invalid Entry");
                break;
            }
            break;
        default://merg
            outputFunction(COMMON_SPOT-1,0,1,COMMON_SPOT,0,"Invalid Entry");
            break;
        }
///NOTE_D:



        //////////////////////////////////////////////////////////////////////////////////////////////////////
        ///Simulate Entities
        //////////////////////////////////////////////////////////////////////////////////////////////////////



        //////////////////////////////////////////////////////////////////////////////////////////////////////
        ///Simulate Points
        //////////////////////////////////////////////////////////////////////////////////////////////////////
            //simulate particle interactions; move/implement all this code with the physics engine.


///NOTE_C:



        //////////////////////////////////////////////////////////////////////////////////////////////////////
        ///Check Each Point And Correct
        //////////////////////////////////////////////////////////////////////////////////////////////////////

        /*do below for nodes on entities as well.*/

        for (int i = 0; i < PARTICLE_COUNT; i++)
        {
            correctMovingPoint(&particles[i]);
        }



        //////////////////////////////////////////////////////////////////////////////////////////////////////
        ///Update List Of Connected Servers... Server Locations Determined By Alg. Involving IP Adress
        //////////////////////////////////////////////////////////////////////////////////////////////////////



        //////////////////////////////////////////////////////////////////////////////////////////////////////
        ///Correct Geometry To Add Servers Or Remove Servers
        //////////////////////////////////////////////////////////////////////////////////////////////////////



        //////////////////////////////////////////////////////////////////////////////////////////////////////
        ///Send Data
        //////////////////////////////////////////////////////////////////////////////////////////////////////



        //////////////////////////////////////////////////////////////////////////////////////////////////////
        ///Recieve Data
        //////////////////////////////////////////////////////////////////////////////////////////////////////
///        connectionRequest = 1;

    }

    //dealoc ncurses mem
    endwin();

    return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////////////
///Functions
//////////////////////////////////////////////////////////////////////////////////////////////////////

//Correct point location and velocity vector if it leaves the cube.
inline void correctMovingPoint(particle *point)
{
    //check for x boundary escape
    if (point->X > 1 or point->X < -1)
    {
        point->Vx = -(point->Vx);
    }
    else if (point->Y > 1 or point->Y < -1)
    {
        point->Vy = -(point->Vy);
    }
    else if (point->Z > 1 or point->Z < -1)
    {
        point->Vz = -(point->Vz);
    }
}

inline bool requestConnection(char *serverIP)
{
    printw("\nAttempting to connect to %s...", serverIP);

    printw("\n\nCommand not fully implemented!\n\n");
    //connectedServerIPs.push_back(serverIP);
}

inline void outputFunction(int y, int x, bool bClear, int y2, int x2, std::string output)
{
    move(y,x);
    if (bClear)
        clrtobot();
    mvprintw(y2,x2,output.c_str());
    refresh();
}
